package javavis.jip3d.gui.dataobjects;

import java.io.FileReader;
import java.io.FileWriter;
import java.io.IOException;
import java.io.Reader;
import java.io.StreamTokenizer;

import javavis.jip3d.geom.MyTransform;
import javavis.jip3d.geom.Neuron3D;
import javavis.jip3d.gui.ScreenData;
import javavis.jip3d.gui.ScreenOptions;

import javax.media.j3d.GeometryArray;
import javax.media.j3d.LineArray;
import javax.media.j3d.PointArray;
import javax.media.j3d.Shape3D;
import javax.media.j3d.TransformGroup;
import javax.vecmath.Color3f;
import javax.vecmath.Point3f;
/**
 * NeuronSet3D Class
 * @author Miguel Cazorla
 *
 */
public class NeuronSet3D extends ScreenData {
	private static final long serialVersionUID = 4135526725951827644L;
	
	// Count the relations between neurons
	/**
	 * @uml.property  name="conexions"
	 */
	private int conexions;
	
	public NeuronSet3D(ScreenOptions opt) {
		super(opt);
		opt.color = new Color3f(0,1,0);
		this.setType(ScreenOptions.tNEURONSET3D);
	}

	@Override
	protected TransformGroup paint() {
		TransformGroup tgRet=new TransformGroup();
		Object []elements = data.elements();
		Point3f []points;
		points = new Point3f[elements.length];
		PointArray geometria;
		LineArray geomlines;
		Neuron3D[] n3dNeighbors;
		Neuron3D n3d;
		Point3f[] puntos = new Point3f[2];
		int contConexions=0;

		geometria = new PointArray(elements.length, PointArray.COORDINATES);
		geomlines = new LineArray(conexions*2, LineArray.COORDINATES|LineArray.COLOR_3);
		
		for(int cont=0; cont<elements.length; cont++) {
			n3d = (Neuron3D)elements[cont];
			points[cont] = new Point3f(n3d.getCoordsf());
			n3dNeighbors=n3d.getNeuronNeighbors();
			for (int n=0; n<n3dNeighbors.length; n++) {
				puntos[0] = new Point3f(n3d.getCoordsf());
				puntos[1] = new Point3f(n3dNeighbors[n].getCoordsf());
				if (contConexions>conexions) System.out.println("me he pasado "+cont);
				geomlines.setCoordinates(contConexions*2, puntos);
				geomlines.setColor(contConexions*2, scr_opt.color);
				geomlines.setColor(contConexions*2 + 1, scr_opt.color);
				contConexions++;
			}
		}

		geometria.setCoordinates(0, points);
		Shape3D forma = new Shape3D(geometria,object_app);
		forma.setCapability(Shape3D.ALLOW_GEOMETRY_READ);
		tgRet.addChild(forma);
		
		forma = new Shape3D(geomlines,this.object_app);
		forma.getGeometry().setCapability(GeometryArray.ALLOW_COORDINATE_READ);
		forma.getGeometry().setCapability(GeometryArray.ALLOW_COUNT_READ);
		forma.getGeometry().setCapability(GeometryArray.ALLOW_FORMAT_READ);
		tgRet.addChild(forma);

		return tgRet;
	}

	@Override
	public int readData(String file_name, String path) {
		Reader fr;
		StreamTokenizer st;
		int num_neurons;
		Neuron3D n3d;
		Neuron3D[] n3dSet, n3dSetAux;
		int[] neighbors;
		
		name = file_name;

		try
		{
			fr=new FileReader(path+file_name);
			st=new StreamTokenizer(fr);
			String comentario="#";
			byte []bcom=comentario.getBytes();
			int icom=(int)bcom[0];
			st.commentChar(icom);
			//Ignore first line
			st.nextToken();
			
			// Number of neurons
			st.nextToken();
			num_neurons=(int)st.nval;
			
			n3dSet= new Neuron3D[num_neurons];
			
			// First, read the neurons
			for (int i=0; i<num_neurons; i++) {
				st.nextToken();
				if(st.sval.compareTo("nousada")!=0)
				{
					n3d = new Neuron3D(st, i);
					data.insert(n3d.getCoords(), n3d);
					n3dSet[i]=n3d;
				}
				else
					n3dSet[i] = null;
			}
			
			// Then, assign the neighbor neurons
			for (int i=0; i<num_neurons; i++) {
				if(n3dSet[i]!=null)
				{
					n3dSetAux=new Neuron3D[n3dSet[i].getNeighbors().length];
					neighbors=n3dSet[i].getNeighbors();
					conexions += n3dSetAux.length;
					for (int n=0; n<n3dSetAux.length; n++) {
						n3dSetAux[n]=n3dSet[neighbors[n]];
					}
					n3dSet[i].setNeuronNeighbors(n3dSetAux);
				}
			}
			
			scr_opt.num_points = data.size();

		} catch (IOException e) {
			System.out.println("Neuron3D::readData Error: can not read data from "+path+file_name);
			return -1;
		}

		return data.size();
	}

	@Override
	public void writeData(String name, String path) {
		if(path.charAt(path.length()-1)!='/')
			path += '/';

		FileWriter fw;
		try
		{
			fw = new FileWriter(path+name);
			fw.write(data.size()+" ");
			fw.write("\n");

			for (Neuron3D f2d : (Neuron3D[])data.elements()) 
				fw.write(f2d.toString()+"\n");

			fw.close();

		} catch(IOException e) {
			System.err.println("Error:" + e.getMessage());
		}

	}

	@Override
	public void applyTransform(MyTransform trans) {
		Object []elements;
		Neuron3D element;
		elements = elements();

		for(int cont=0;cont<elements.length;cont++)
		{
			element = (Neuron3D)elements[cont];
			element.applyTransform(trans);
		}
	}

}